使用 room 來建立Database
abstract class AppDatabase: RoomDatabase() {
companion object {
private const val DATABASE_NAME = "_db"
// For Singleton instantiation
@Volatile private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
instance ?: buildDatabase(context).also { instance = it }
}
}
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME).build()
}
}
abstract fun peopleDao(): PeopleDao
}
//建立table 所需要的欄位
@Entity(
tableName = Person.TABLE_NAME
)
data class Person (
@ColumnInfo(name = COLUMN_Name) var title: String,
@ColumnInfo(name = COLUMN_CREATED_DATE) var createdDate: Date
) {
companion object {
const val TABLE_NAME = "person"
const val COLUMN_ID = "id"
const val COLUMN_NAME = "name"
const val COLUMN_CREATED_DATE = "created_date"
}
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = COLUMN_ID) var id: Int = 0
}
// 實作 新增與查詢
class PersonRepository(
private val database: AppDatabase
) {
suspend fun insertPerson(person: Person) {
database.peopleDao().insert(person)
}
suspend fun updatePerson(person: Person) {
database.peopleDao().update(person)
}
fun getAll(): LiveData<List<Person>> {
return database.peopleDao().findAll()
}
}
ViewModel conncet repository Data
class PeopleViewModel(private val repository: PersonRepository) : ViewModel() {
private val title = Person.Title("聯絡人清單")
val todoLiveData: LiveData<List<Todo>> = MediatorLiveData<List<Todo>>().apply {
val source = repository.getAll().map {
it.map { person ->
Person.Item(
person.id,
person.name,
person.done,
person.createdDate
)
}
}
addSource(source) {
this.value = mutableListOf(title) + it
}
value = mutableListOf(title)
}
fun createNewTodo(name: String) {
val person = Person(
name = name,
createdDate = Date()
)
viewModelScope.launch {
repository.insertPerson(person)
}
}
fun updateTodo(person: Person.Item) {
val person = Person(
name = person.name,
createdDate = person.createdDate
).apply { id = person.id }
viewModelScope.launch {
repository.updatePerson(person)
}
}
}
從DB讀取資料,顯示清單頁 data放入recyclerView
class ListFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...........
val peopleDb = AppDatabase.getInstance(requireActivity().applicationContext)
val peopleRepo = PersonRepository(peopleDb)
val viewModelFactory = AnyViewModelFactory {
peopleViewModel(peopleRepo)
}
// recyclerView ListAdapter Listener data change
val adapter = PersonAdapter().apply {
onTodoChangeListener = object : OnTodoChangeListener {
override fun onChange(person: Person.Item) {
peopleViewModel.updateTodo(person)
}
}
}
recyclerView.adapter = adapter
recyclerView.layoutManager =
LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
recyclerView.addItemDecoration(
DividerItemDecoration(
requireContext(),
LinearLayoutManager.VERTICAL
)
)
val peopleViewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(PeopleViewModel::class.java)
peopleViewModel.personLiveData.observe(viewLifecycleOwner, Observer { todos: List<Todo> ->
adapter.submitList(todos)
})
}
}
新增頁面,點選新增按鈕
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
.....
val peopleDb = AppDatabase.getInstance(requireActivity().applicationContext)
val peopleRepo = PersonRepository(peopleDb)
val viewModelFactory = AnyViewModelFactory {
peopleViewModel(peopleRepo)
}
val peopleViewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(PeopleViewModel::class.java)
........
buttonAdd.setOnClickListener {
if (name.text.isNullOrEmpty()) {
name.error = "尚未填寫新增聯絡人"
} else {
name.error = null
val name = name.text.toString()
peopleViewModel.createNewPerson(name)
findNavController().popBackStack()
}
}
}
資料存在app db 裡, app 關掉再打開後資料仍存在,完成簡單新增聯絡人
reference:https://www.notion.so/Navigation-component-9-9-Andy-a1245a1b31c5453fbf1b28f887ec0d73
reference:https://enginebai.com/2019/04/03/android-database-room/
reference:https://givemepass.blogspot.com/2015/12/recyclerview.html
reference:https://medium.com/evan-android-note/android-fragment-%E5%85%B1%E7%94%A8-viewmodel-19a6d9161421